#pragma once
#include "Thread_pool.hpp"
#include <queue>


const int g_pthreadnum = 5;

pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;

// 线程池
template <class T>
class ThreadPool
{
public:
    void Everydo(string name)
    {
        while (true)
        {
            Lock();

            while (qtask.empty() && state)
            {
                waitnum++;
                Wait_Pthread();
                waitnum--;
            }

            if (qtask.empty() && !state)
            {
                UnLock();
                cout << name << ": quit" << endl;
                break;
            }

            T task = qtask.front();
            qtask.pop();

            UnLock();

            task();      
        }
    }

    bool Push(const T &t)
    {
        Lock();

        bool ret = false;
        if (state)
        {
            qtask.push(t);
            if (waitnum > 0)
                WakeUp_sigle();

            ret = true;
        }

        UnLock();
        return ret;
    }

    void ThreadInit()
    {
        for (int i = 0; i < pthreadnum; i++)
        {
            string name = "pthread-" + to_string(i);
            vthread.emplace_back(bind(&ThreadPool::Everydo, this, placeholders::_1), name); // 每个线程都要执行这个方法，这个方法会将任务队列中的任务分配给他们
        }
    }

    void Wait()
    {
        for (auto &e : vthread)
            e.Join();
    }

    void Quit()
    {
        state = false;
        WakeUp_All();
    }

    void Start()
    {
        state = true;
        for (auto &e : vthread)
            e.Start();
    }

    static ThreadPool *GetPool()
    {
        if (pth == nullptr)
        {
            pthread_mutex_lock(&mutex);
            if (pth == nullptr)
            {
                pth = new ThreadPool();
                cout << "Create" << endl;
            }
            pthread_mutex_unlock(&mutex);
        }

        cout << "Get" << endl;
        return pth;
    }

private:
    // 线程池需要什么？线程数量，保存线程的容器
    int pthreadnum;
    vector<Thread> vthread;

    // 一个任务队列,创建线程池对象时，线程创建好，我们需要从外部接收任务分配给线程执行
    // 我们希望能够接收任意类型的任务，仿函数，函数，lambda表达式等，所以使用模板
    queue<T> qtask;

    // 一个状态，控制线程池的退出
    bool state;
    int waitnum;

    ThreadPool(int num = g_pthreadnum)
        : pthreadnum(num), state(false), waitnum(0)
    {
    }

    void Lock()
    {
        pthread_mutex_lock(&mutex);
    }

    void UnLock()
    {
        pthread_mutex_unlock(&mutex);
    }

    void WakeUp_sigle()
    {
        pthread_cond_signal(&cond);
    }

    void WakeUp_All()
    {
        pthread_cond_broadcast(&cond);
    }

    void Wait_Pthread()
    {
        pthread_cond_wait(&cond, &mutex);
    }

    static ThreadPool *pth;
    static pthread_mutex_t mutex;
};

template <class T>
ThreadPool<T> *ThreadPool<T>::pth = nullptr;

template <class T>
pthread_mutex_t ThreadPool<T>::mutex = PTHREAD_MUTEX_INITIALIZER;





// const int defalutnum = 6;
// pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
// pthread_cond_t cond = PTHREAD_COND_INITIALIZER;

// template<class T>
// class ThreadPool
// {
// public:
//     ThreadPool(){}
//     ThreadPool(int num = defalutnum)
//         :threadnum(num)
//     {}

//     //由多线程执行,构造时传递给线程
//     void Handler(string name)
//     {
//         while(true)
//         {
//             Lock();
//             //任务队列为空 && 线程池未退出
//             while(q_task.empty() && running)
//             {
//                 waitnum++;
//                 Wait_Pthread();
//                 waitnum--;
//             }

//             //任务队列为空 && 线程池退出 ------>线程break退出，否则执行任务
//             if(q_task.empty() && !running)
//             {
//                 UnLock();
//                 cout << name << " quit" << endl;
//                 sleep(1);
//                 break;
//             }

//             //任务队列有任务，无论线程池是否退出，均要继续执行任务
//             T task = q_task.front();
//             q_task.pop();

//             //执行任务

//             UnLock();
//         }
//     }

//     void ThreadInit()
//     {
//         for(int i=0; i<threadnum; i++)
//         {
//             string name = "thread->" + to_string(i);
//             v_thread.emplace_back(bind(&ThreadPool::Handler, this, placeholders::_1), name);
//         }
//     }

//     void Start()
//     {
//         running = true;
//         for(auto &e : v_thread) e.Start();
//     }

//     //多线程调用使用
//     bool Push(const T& task)
//     {
//         bool ret = false;
//         Lock();

//         if(running)
//         {
//             q_task.push(task);
//             if(waitnum > 0) WakeUp_sigle();

//             ret = true;
//         }

//         UnLock();
//         return ret;
//     }

//     void Stop()
//     {
//         Lock();
//         running = false;
//         WakeUp_All(); //多线程调用，如果不加锁，去执行Handler分配的任务，由于任务有锁，实际上似乎并不影响。
//         UnLock();
//     }

//     void Wait()
//     {
//         for(auto &e : v_thread) e.Join();
//     }

// private:
//     int threadnum;
//     vector<Thread> v_thread;
//     queue<T> q_task;

//     int waitnum = 0;
//     bool running = false;

//     void Lock()
//     {
//         pthread_mutex_lock(&mutex);
//     }

//     void UnLock()
//     {
//         pthread_mutex_unlock(&mutex);
//     }

//     void WakeUp_sigle()
//     {
//         pthread_cond_signal(&cond);
//     }

//     void WakeUp_All()
//     {
//         pthread_cond_broadcast(&cond);
//     }

//     void Wait_Pthread()
//     {
//         pthread_cond_wait(&cond, &mutex);
//     }

// };